package cm.processor;

import cm.dto.XxlJobInfoDTO;
import com.xxl.job.core.handler.IJobHandler;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Job注册中心
 * 扫描所有实现IJobHandler接口的类，读取其@XxlJob注解，注册到调度中心
 * 同时解析Job所属的服务名（通过FeignClient注解或字段名匹配）
 */
@Slf4j
@Component
public class XxlJobAnnotationProcessor implements BeanPostProcessor {
    /**
     * 服务名到Job列表的映射
     */
    @Getter
    private final Map<String, List<XxlJobInfoDTO>> serviceJobsMap = new ConcurrentHashMap<>();
    /**
     * Job处理器名称到Job信息的映射
     */
    @Getter
    private final Map<String, XxlJobInfoDTO> jobHandlerMap = new ConcurrentHashMap<>();
    /**
     * Feign客户端Bean名称到服务名的映射
     */
    private Map<String, String> feignClientToServiceMap;

    @Autowired
    private ApplicationContext context;

    @PostConstruct
    public void init() {
        this.feignClientToServiceMap = buildFeignClientServiceMap(context);
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        // 1. 检查是否是IJobHandler实现类
        if (bean instanceof IJobHandler) {
            IJobHandler handler = (IJobHandler) bean;
            Class<?> handlerClass = handler.getClass();

            // 2. 查找@XxlJob注解
            Method executeMethod = null;
            try {
                executeMethod = handlerClass.getMethod("execute");
                XxlJob xxlJob = executeMethod.getAnnotation(XxlJob.class);
                if (xxlJob != null) {
                    String jobHandlerName = xxlJob.value();
                    String serviceName = resolveServiceName(handler, feignClientToServiceMap);

                    XxlJobInfoDTO jobInfoDTO = new XxlJobInfoDTO(jobHandlerName, handler.getClass().getSimpleName(), serviceName);
                    serviceJobsMap.computeIfAbsent(serviceName, k -> new ArrayList<>()).add(jobInfoDTO);
                    jobHandlerMap.put(jobHandlerName, jobInfoDTO);
                }
            } catch (NoSuchMethodException e) {
                log.error(e.getMessage(), e);
            }
        }
        return bean;
    }

    /**
     * 构建Feign客户端到服务名的映射
     *
     * @param context
     * @return
     */
    public Map<String, String> buildFeignClientServiceMap(ApplicationContext context) {
        Map<String, String> map = new HashMap<>();
        String[] feignClientNames = context.getBeanNamesForAnnotation(FeignClient.class);
        for (String beanName : feignClientNames) {
            FeignClient feignClient = context.findAnnotationOnBean(beanName, FeignClient.class);
            String serviceName = feignClient.value().isEmpty() ? feignClient.name() : feignClient.value();
            map.put(beanName, serviceName);
        }
        return map;
    }

    /**
     * 解析Job所属的服务名
     *
     * @param handler
     * @param feignClientMap
     * @return
     */
    private String resolveServiceName(IJobHandler handler, Map<String, String> feignClientMap) {
        // 反射获取Job类中所有字段
        for (Field field : handler.getClass().getDeclaredFields()) {
            field.setAccessible(true);
            try {
                Object fieldValue = field.get(handler);
                if (fieldValue == null) continue;

                // 检查字段是否是Feign客户端
                FeignClient feignClient = field.getAnnotation(FeignClient.class);
                if (feignClient != null) {
                    return feignClient.value().isEmpty() ? feignClient.name() : feignClient.value();
                }

                // 或者通过Bean名称匹配
                String typeName = field.getAnnotatedType().getType().getTypeName();
                if (feignClientMap.containsKey(typeName)) {
                    return feignClientMap.get(typeName);
                }
            } catch (IllegalAccessException e) {
                log.error("Failed to access field {} of job handler {}", field.getName(), handler.getClass().getSimpleName(), e);
            }
        }
        return "unknown-service";
    }
}
